/*
 * Copyright (c) 2022-2022 All rights Reserved.
 */

package com.driving.core.service.impl;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Random;
import java.util.Set;
import java.util.stream.Collectors;

import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.driving.core.base.BaseServiceImpl;
import com.driving.core.entity.Exercise;
import com.driving.core.entity.ExerciseCollection;
import com.driving.core.entity.ExerciseExam;
import com.driving.core.exception.DrivingException;
import com.driving.core.mapper.IExerciseCollectionMapper;
import com.driving.core.mapper.IExerciseExamMapper;
import com.driving.core.mapper.IExerciseMapper;
import com.driving.core.service.IExerciseService;
import com.driving.core.util.Constant;
import com.driving.core.util.Constant.ExerciseStatus;
import com.driving.core.util.Constant.ExerciseType;
import com.driving.core.util.MessageType.ExceptionType;
import com.driving.core.util.MessageType.InformationType;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

/**
 * @author SAGITTAR
 * @since 2017
 */
@Slf4j
@RequiredArgsConstructor
@Service(value = "exerciseService")
public class ExerciseServiceImpl extends BaseServiceImpl<IExerciseMapper, Exercise> implements IExerciseService {

    private final IExerciseCollectionMapper exerciseCollectionMapper;

    private final IExerciseExamMapper exerciseExamMapper;

    @Override
    public Map<String, Object> selectDistinctChapterBySubjectId(int subjectId, String type) {
        List<Map<String, Object>> chapterList = baseMapper
                .selectChapterBySubjectIdAndType(subjectId, getType(subjectId, type)).stream().map(chapter -> {
                    Map<String, Object> map = new HashMap<>(4);
                    map.put("id", chapter);
                    map.put("name", toChinese(type, chapter));
                    return map;
                }).collect(Collectors.toList());
        return Collections.singletonMap("list", chapterList);
    }

    @Override
    public Map<String, Object> selectRandomOrNextOne(int subjectId, String type, int chapter, int category,
            int studentId, int id) {
        // 组装查询参数
        QueryWrapper<Exercise> wrapper = new QueryWrapper<>();
        wrapper.eq("subject_id", subjectId);
        wrapper.eq("type", getType(subjectId, type));
        wrapper.eq(chapter != -1, "chapter", chapter);
        wrapper.eq(category != -1, "category", category);
        wrapper.orderByAsc("id");
        // 查询到“下一题”
        List<Exercise> exerciseList = list(wrapper);
        int totalSize = exerciseList.size();
        int randomOrNextId = getRandomIndex(id, totalSize);
        Exercise randomOrNextExercise = exerciseList.get(randomOrNextId);
        // 组装所有信息
        Map<String, Object> result = new HashMap<>(4);
        result.put("count", totalSize);
        result.put("hasNext", id < totalSize);
        result.put("exercise", getExerciseMap(randomOrNextExercise, studentId));
        return result;
    }

    @Override
    public Map<String, Object> selectIncorrectOrCollectedOne(int studentId, int subjectId, int from, int id) {
        List<Map<String, Object>> exerciseList = baseMapper.selectIncorrectOrCollectedList(studentId, subjectId, from);
        int totalSize = exerciseList.size();
        if (totalSize <= 0) {
            throw new DrivingException(configReader.getInfoMessage(InformationType.NO_INCORRECT_COLLECTED));
        }
        int nextId = getRandomIndex(id, totalSize);
        Map<String, Object> exerciseMap = exerciseList.get(nextId);
        // 组装试题结果
        Object exerciseId = exerciseMap.get("id");
        log.info("查询题目编号为{}的题目", exerciseId);
        Map<String, Object> exercise = new HashMap<>(12);
        exercise.put("id", exerciseId);
        exercise.put("title", exerciseMap.get("title"));
        exercise.put("choiceList", trimBracketsAndToList(exerciseMap.get("choice_list")));
        exercise.put("answer", exerciseMap.get("answer"));
        exercise.put("explanation", exerciseMap.get("explanation"));
        exercise.put("picture", exerciseMap.get("picture"));
        exercise.put("incorrectOrCollectionId", exerciseMap.get("incorrectOrCollectionId"));
        // 组装所有信息
        Map<String, Object> result = new HashMap<>(4);
        result.put("count", totalSize);
        result.put("hasNext", id < totalSize);
        result.put("exercise", exercise);
        return result;
    }

    /**
     * 返回指定范围的随机值
     *
     * @param id id
     * @param totalSize totalSize
     * @return 返回指定范围的随机值
     */
    private int getRandomIndex(int id, int totalSize) {
        if (0 >= totalSize || id > totalSize) {
            throw new DrivingException(configReader.getExceptionMessage(ExceptionType.NEXT_EXERCISE_NOT_FOUND));
        }
        return id <= 0 ? new Random().nextInt(totalSize) : id - 1;
    }

    /**
     * 数字转汉字
     *
     * @param number number
     * @return 数字转汉字
     */
    private String toChinese(String type, int number) {
        String chinese = null;
        switch (number) {
        case 1:
            chinese = "一";
            break;
        case 2:
            chinese = "二";
            break;
        case 3:
            chinese = "三";
            break;
        case 4:
            chinese = "四";
            break;
        case 5:
            chinese = "五";
            break;
        case 6:
            chinese = "六";
            break;
        case 7:
            chinese = "七";
            break;
        case 8:
            chinese = "八";
            break;
        case 9:
            chinese = "九";
            break;
        default:
            break;
        }
        if (StringUtils.isNotBlank(chinese)) {
            chinese = StringUtils.join("第", chinese, "章");
        }
        if (StringUtils.equals(type, "C1") || StringUtils.equals(type, "C2")) {
            switch (number) {
            case 1:
                chinese = "道路交通安全法律、法规和规章";
                break;
            case 2:
                chinese = "道路交通信号";
                break;
            case 3:
                chinese = "安全行车、文明驾驶基础知识";
                break;
            case 4:
                chinese = "机动车驾驶操作相关基础知识";
                break;
            default:
                break;
            }
        }
        return chinese;
    }

    /**
     * 将原始选项转为列表形式
     *
     * @param source 原始选项
     * @return 将原始选项转为列表形式
     */
    private List<String> trimBracketsAndToList(Object source) {
        String choice = StringUtils.substringBetween(String.valueOf(source), "[", "]").trim();
        return Arrays.stream(choice.split(",")).map(String::trim).collect(Collectors.toList());
    }

    /**
     * 获取完全车型
     *
     * @param subjectId subjectId
     * @param type type
     * @return 获取完全车型
     */
    private String getType(int subjectId, String type) {
        String completeType = null;
        if (1 == subjectId) {
            if (StringUtils.equals("A1", type) || StringUtils.equals("A3", type) || StringUtils.equals("B1", type)) {
                completeType = "A1-A3-B1";
            }
            if (StringUtils.equals("A2", type) || StringUtils.equals("B2", type)) {
                completeType = "A2-B2";
            }
            if (StringUtils.equals("C1", type) || StringUtils.equals("C2", type)) {
                completeType = "C1-C2";
            }
        }
        if (4 == subjectId) {
            if (StringUtils.equals("A1", type) || StringUtils.equals("A2", type) || StringUtils.equals("A3", type)
                    || StringUtils.equals("B1", type) || StringUtils.equals("B2", type)) {
                completeType = "A1-A2-A3-B1-B2";
            }
            if (StringUtils.equals("C1", type) || StringUtils.equals("C2", type)) {
                completeType = "C1-C2";
            }
        }
        return completeType;
    }

    @Override
    public Map<String, Object> selectSimulationBySubjectIdAndType(int subjectId, String type) {
        QueryWrapper<ExerciseExam> examWrapper = new QueryWrapper<>();
        examWrapper.eq("subject_id", subjectId);
        examWrapper.eq("type", getType(subjectId, type));
        List<ExerciseExam> examList = exerciseExamMapper.selectList(examWrapper);
        List<Map<String, Object>> examMapList = new ArrayList<>(examList.size());
        for (int index = 0; index < examList.size(); index++) {
            Map<String, Object> examMap = new HashMap<>(4);
            examMap.put("examId", examList.get(index).getId());
            examMap.put("title", String.format("第%s套", index + 1));
            examMapList.add(examMap);
        }
        Map<String, Object> result = new HashMap<>(4);
        result.put("count", examList.size());
        result.put("list", examMapList);
        return result;
    }

    @Override
    public Map<String, Object> selectSimulationOneByExamIdAndId(int examId, int id) {
        ExerciseExam exerciseExam = exerciseExamMapper.selectById(examId);
        if (Objects.isNull(exerciseExam)) {
            throw new DrivingException(configReader.getExceptionMessage(ExceptionType.NEXT_EXERCISE_NOT_FOUND));
        }
        String[] idArray = StringUtils.substringBetween(exerciseExam.getExerciseIds(), "[", "]").split(",");
        List<Integer> idList = Arrays.stream(idArray).map(a -> Integer.parseInt(a.trim())).collect(Collectors.toList());
        if (id <= 0) {
            id = idList.get(0);
        }
        int index = idList.indexOf(id);
        if (index == -1) {
            throw new DrivingException(configReader.getExceptionMessage(ExceptionType.NEXT_EXERCISE_NOT_FOUND));
        }
        Exercise exercise = getById(id);
        if (Objects.isNull(exercise)) {
            throw new DrivingException(configReader.getExceptionMessage(ExceptionType.NEXT_EXERCISE_NOT_FOUND));
        }
        Integer nextId = null;
        if (index < 99) {
            nextId = idList.get(index + 1);
        }
        Map<String, Object> result = getExerciseMap(exercise, -1);
        result.put("nextId", nextId);
        return result;
    }

    private String getTitle(int pictureType) {
        String title = null;
        switch (pictureType) {
        case 1:
            title = "交通标志试题";
            break;
        case 2:
            title = "汽车仪表指示灯试题";
            break;
        case 3:
            title = "交警手势类试题";
            break;
        case 4:
            title = "交通事故图解试题";
            break;
        default:
            break;
        }
        return title;
    }

    @Override
    public Map<String, Object> selectListByPictureType(int subjectId, String type) {
        QueryWrapper<Exercise> exerciseWrapper = new QueryWrapper<>();
        String conditionColumn = "picture_type";
        exerciseWrapper.isNotNull(conditionColumn).or().ne(conditionColumn, StringUtils.EMPTY);
        List<Exercise> exerciseList = baseMapper.selectList(exerciseWrapper);
        Set<Integer> pictureTypeSet = exerciseList.stream().map(Exercise::getPictureType).collect(Collectors.toSet());
        List<Map<String, Object>> pictureTypeList = pictureTypeSet.stream().map(pictureType -> {
            Map<String, Object> exerciseMap = new HashMap<>(8);
            exerciseMap.put("pictureType", pictureType);
            exerciseMap.put("title", getTitle(pictureType));
            List<Exercise> currentExerciseList = exerciseList.stream().filter(e -> e.getPictureType() == pictureType)
                    .collect(Collectors.toList());
            exerciseMap.put("count", currentExerciseList.size());
            List<Map<String, Object>> pictureList = currentExerciseList.stream().map(e -> {
                Map<String, Object> picture = new HashMap<>(4);
                picture.put("id", e.getId());
                picture.put("picture", e.getPicture());
                return picture;
            }).collect(Collectors.toList());
            if (pictureList.size() > 4) {
                pictureList = pictureList.subList(0, 4);
            }
            exerciseMap.put("pictureList", pictureList);
            return exerciseMap;
        }).collect(Collectors.toList());
        return Collections.singletonMap("list", pictureTypeList);
    }

    @Override
    public Map<String, Object> selectAllByPictureType(int pictureType) {
        QueryWrapper<Exercise> exerciseWrapper = new QueryWrapper<>();
        exerciseWrapper.eq("picture_type", pictureType);
        List<Exercise> exerciseList = baseMapper.selectList(exerciseWrapper);
        List<Map<String, Object>> pictureList = exerciseList.stream().map(e -> {
            Map<String, Object> picture = new HashMap<>(4);
            picture.put("id", e.getId());
            picture.put("picture", e.getPicture());
            return picture;
        }).collect(Collectors.toList());
        Map<String, Object> result = new HashMap<>(8);
        result.put("pictureType", pictureType);
        result.put("count", exerciseList.size());
        result.put("title", getTitle(pictureType));
        result.put("pictureList", pictureList);
        return result;
    }

    @Override
    public Map<String, Object> selectOneById(int studentId, int id) {
        Exercise exercise = baseMapper.selectById(id);
        if (Objects.isNull(exercise)) {
            throw new DrivingException(configReader.getExceptionMessage(ExceptionType.NEXT_EXERCISE_NOT_FOUND));
        }
        return getExerciseMap(exercise, studentId);
    }

    /**
     * 获取试题信息
     *
     * @param exercise exercise
     * @param studentId studentId
     * @return 获取试题信息
     */
    private Map<String, Object> getExerciseMap(Exercise exercise, int studentId) {
        int id = exercise.getId();
        log.info("查询题目编号为{}的题目", id);
        Map<String, Object> result = new HashMap<>(12);
        result.put("id", id);
        result.put("title", exercise.getTitle());
        result.put("choiceList", exercise.getChoiceList());
        result.put("answer", exercise.getAnswer());
        result.put("explanation", exercise.getExplanation());
        result.put("picture", exercise.getPicture());
        Integer incorrectOrCollectionId = null;
        if (studentId >= 0) {
            // 查询条件
            LambdaQueryWrapper<ExerciseCollection> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(ExerciseCollection::getStudentId, studentId);
            wrapper.eq(ExerciseCollection::getExerciseId, id);
            wrapper.eq(ExerciseCollection::getFrom, ExerciseType.COLLECTION);
            wrapper.eq(ExerciseCollection::getStatus, ExerciseStatus.NOT_DELETED);
            ExerciseCollection collection = exerciseCollectionMapper.selectOne(wrapper);
            if (Objects.nonNull(collection)) {
                incorrectOrCollectionId = collection.getId();
            }
        }
        result.put("incorrectOrCollectionId", incorrectOrCollectionId);
        return result;
    }

    @Override
    public int collect(int studentId, int exerciseId, int from) {
        QueryWrapper<ExerciseCollection> collectionWrapper = new QueryWrapper<>();
        collectionWrapper.eq("student_id", studentId);
        collectionWrapper.eq("exercise_id", exerciseId);
        collectionWrapper.eq("`from`", from);
        collectionWrapper.eq("status", Constant.ExerciseStatus.NOT_DELETED);
        List<ExerciseCollection> collectionList = exerciseCollectionMapper.selectList(collectionWrapper);
        if (Objects.nonNull(collectionList) && !collectionList.isEmpty()) {
            throw new DrivingException(configReader.getInfoMessage(InformationType.ALREADY_COLLECTED));
        }
        int generatedId = -1;
        ExerciseCollection collection = new ExerciseCollection(studentId, exerciseId, from);
        if (retBool(exerciseCollectionMapper.insert(collection))) {
            generatedId = collection.getId();
        }
        return generatedId;
    }

    @Override
    public boolean cancelCollect(int studentId, int id) {
        ExerciseCollection collection = exerciseCollectionMapper.selectById(id);
        // 不是该学员收藏的题目
        if (Objects.isNull(collection) || collection.getStudentId() != studentId) {
            throw new DrivingException(configReader.getExceptionMessage(ExceptionType.NOT_COMPLETE));
        }
        return retBool(baseMapper.deleteById(id));
    }
}
